package com.sxbbc.plat.util;

import com.sxbbc.common.basics.exceptions.ThrowJsonException;
import com.sxbbc.common.basics.utils.date.DateUtil;
import com.sxbbc.common.core.entity.jz.SysLogs;
import com.sxbbc.common.core.entity.jz.SysUser;
import com.sxbbc.common.core.service.ISysLogsService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 日志
 *
 * @author leehao
 * @date 2019-04-28 11:03
 */
@Aspect
public class LogAopAction {

    /**
     * 获取开始时间
     */
    private long BEGIN_TIME;


    /**
     * 获取结束时间
     */
    private long END_TIME;

    /**
     * 定义本次log实体
     */
    private SysLogs log = new SysLogs();

    @Pointcut("@annotation(com.sxbbc.plat.util.SystemLog)")
    private void controllerAspect() {
    }

    @Autowired
    private ISysLogsService sysLogsService;

    /**
     * 方法开始执行
     */
    @Before("controllerAspect()")
    public void doBefore() {
        BEGIN_TIME = DateUtil.getInstance().currentTimeMillis();
    }

    /**
     * 方法结束执行
     */
    @After("controllerAspect()")
    public void after() {
        END_TIME = DateUtil.getInstance().currentTimeMillis();
    }

    /**
     * 方法执行结束后
     */
    @AfterReturning("controllerAspect()")
    public void doAfter() {
        if (log != null) {
            if (log.getStatus() != null) {
                if (log.getStatus() == 1 || log.getStatus() == -1) {
                    if (RequestContextHolder.getRequestAttributes() != null) {
                        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                        //获取当前登陆用户信息
                        SysUser loginUser = PlatSession.getSysUser(request);
                        if (loginUser == null) {
                            log.setLoginAccount("—— ——");
                        } else {
                            log.setLoginAccount(loginUser.getLogin() + "|" + loginUser.getName());
                        }
                        log.setActionTime(END_TIME - BEGIN_TIME);
                        log.setCreatetime(new Date(BEGIN_TIME));
                        sysLogsService.save(log);
                    }
                }
            }
        }
    }

    /**
     * 方法有异常时的操作
     */
    @AfterThrowing("controllerAspect()")
    public void doAfterThrow() {
    }


    /**
     * 方法执行
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("controllerAspect()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //日志实体对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //禁止爬虫
        //禁止IP
        //检查业务
        //上面是开始业务的前置检验
        //下面是业务检验
        Object object = null;
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            // 拦截的实体类，就是当前正在执行的controller
            Object target = pjp.getTarget();
            // 拦截的方法名称。当前正在执行的方法
            String methodName = pjp.getSignature().getName();
            // 拦截的方法参数
            @SuppressWarnings("unused")
            Object[] args = pjp.getArgs();
            // 拦截的放参数类型
            Signature sig = pjp.getSignature();
            MethodSignature msig = null;
            if (!(sig instanceof MethodSignature)) {
                throw new IllegalArgumentException("该注解只能用于方法");
            }
            msig = (MethodSignature) sig;
            @SuppressWarnings("rawtypes")
            Class[] parameterTypes = msig.getMethod().getParameterTypes();

            Method method = null;
            try {
                method = target.getClass().getMethod(methodName, parameterTypes);
            } catch (SecurityException e1) {
                e1.printStackTrace();
                throw new ThrowJsonException(e1.getMessage());
            }

            if (null != method) {
                // 判断是否包含自定义的注解，SystemLog
                if (method.isAnnotationPresent(SystemLog.class)) {
                    SystemLog systemlog = method.getAnnotation(SystemLog.class);
                    log.setModule(systemlog.module());
                    log.setMethod(systemlog.methods());
                    log.setLoginIp(getIp(request));
                    log.setActionUrl(request.getRequestURI());

                    try {
                        object = pjp.proceed();
                        log.setDescription("执行成功");
                        log.setStatus(1);
                    } catch (Throwable e) {
                        log.setDescription("执行失败");
                        log.setStatus(0);
                        throw new ThrowJsonException(e.getMessage());
                    }
                } else {//没有包含注解
                    object = pjp.proceed();
                    log.setDescription("此操作不包含注解");
                    log.setStatus(-1);
                }
            } else { //不需要拦截直接执行
                object = pjp.proceed();
                log.setDescription("不需要拦截直接执行");
                log.setStatus(-1);
            }
        } else {
            object = pjp.proceed();
        }
        return object;
    }

    /**
     * 获取ip地址
     */
    private String getIp(HttpServletRequest request) {
        if (request.getHeader("x-forwarded-for") == null) {
            return request.getRemoteAddr();
        }
        return request.getHeader("x-forwarded-for");
    }
}
